<?php
namespace ITSociaal\Themes\Houtgrutter;

class TemplateController
{
	/** @var \ITSociaal\Themes\Houtgrutter\RenderController */
	protected $rc;

	/** @var \ITSociaal\Themes\Houtgrutter\Util */
	protected $util;

	/** @var string */
	protected $name;

	/** @var callable[] */
	protected $rendererFactories = [];

	/**
	 * Returns $obj only if valid RendererInterface instance
	 *
	 * @return \ITSociaal\Themes\Houtgrutter\RendererInterface|null
	 */
	protected function filterValidRenderer($obj)
	{
		return is_a($obj, RendererInterface::class)
			? $obj
			: null;
	}

	/**
	 * Returns $obj only if valid PostProcessorInterface instance
	 *
	 * @return \ITSociaal\Themes\Houtgrutter\PostProcessorInterface|null
	 */
	protected function filterValidPostProcessor($obj)
	{
		return is_a($obj, PostProcessorInterface::class)
			? $obj
			: null;
	}

	/**
	 * @param callable $factory
	 *
	 * @return self
	 */
	protected function addRendererFactory(callable $factory)
	{
		$this->rendererFactories[] = $factory;

		return $this;
	}

	/**
	 * @return callable[]
	 */
	public function getRendererFactories()
	{
		return $this->rendererFactories;
	}

	/**
	 * Fills the RenderController with valid objects
	 *
	 * @return self
	 */
	public function findRenderer()
	{
		$util = $this->getUtil();
		$rc = $this->getRenderController();

		foreach (
			$util->generateResultPerMethod(
				$this->getRendererFactories(),
				$this->getName(),
				$util
			) as $result
		) {
			$renderer = $this->filterValidRenderer($result);
			$postproc = $this->filterValidPostProcessor($result);

			!is_object($renderer) or $rc->addRenderer($renderer);
			!is_object($postproc) or $rc->addPostProcessor($postproc);
		}

		return $this;
	}

	/**
	 * Primes the controller with renderer factories
	 *
	 * Should be called before findRenderer()
	 *
	 * @return self
	 */
	public function addDefaultRendererFactories()
	{
		$this->addRendererFactory([GenericRendererFactory::class, "create"]);
		$this->addRendererFactory([WpRendererFactory::class, "create"]);
		$this->addRendererFactory([StringRendererFactory::class, "create"]);

		return $this;
	}

	/**
	 * @param \ITSociaal\Themes\Houtgrutter\Util $util
	 */
	public function __construct(Util $util, RenderController $rc)
	{
		$this->util = $util;
		$this->rc = $rc;
	}

	/**
	 * Does all the things
	 *
	 * @param string                                           $template
	 * @param \ITSociaal\Themes\Houtgrutter\Util               $util
	 * @param \ITSociaal\Themes\Houtgrutter\RenderController   $rc
	 * @param \ITSociaal\Themes\Houtgrutter\TemplateController $self
	 */
	public static function main(
		$template,                        // Should be __FILE__ in caller
		Util $util = null,
		RenderController $rc = null,
		TemplateController $self = null
	) {
		$util = $util ?: new Util;
		$rc   = $rc   ?: new RenderController($util);
		$self = $self ?: new static($util, $rc);

		print($self
			->addDefaultRendererFactories()
			->setName($self->getUtil()->deriveTemplateNameFromPath($template))
			->findRenderer()
			->getRenderController()
			->performRendering()
			->performPostProcessing()
			->getResult());
	}

	/**
	 * @return string
	 * @throws \ITSociaal\Themes\Houtgrutter\Exception\RuntimeException
	 */
	public function getName()
	{
		$ret = $this->name;

		if (is_null($ret)) {
			throw new Exception\RuntimeException(
				"name has not been set"
			);
		}

		return $ret;
	}

	/**
	 * @param string $name
	 *
	 * @return self
	 * @throws \ITSociaal\Themes\Houtgrutter\Exception\InvalidArgumentException
	 */
	public function setName($name)
	{
		$name = (string)$name;

		if (empty($name)) {
			throw new Exception\InvalidArgumentException(
				"\$name should not be empty"
			);
		}

		$this->name = $name;

		return $this;
	}

	/**
	 * @return \ITSociaal\Themes\Houtgrutter\Util
	 */
	protected function getUtil()
	{
		return $this->util;
	}

	/**
	 * @return \ITSociaal\Themes\Houtgrutter\RenderController
	 */
	protected function getRenderController()
	{
		return $this->rc;
	}
}

/* vi:set ts=4 sw=4 noet: */
